home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993 October: Windmill on DISC / ADC Developer CD (1993-10) (''Windmill On DISC'')_iso / Dev.CD Oct 93.iso / System Software / U.S. System Software / System 7 Pro™ Beta 11 / Development Tools / Sample Code / Messaging Service Access Module / Internet PMSAM / Internet PMSAM source / smtp.protocol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-19  |  7.8 KB  |  351 lines  |  [TEXT/MPS ]

  1. /*-------------------------------------------------------------------
  2.  
  3. AOCE Post Office Protocol (POP) / Simple Mail Transfer Protocol (SMTP)
  4. Mail Service Access Module
  5.  
  6. written by Steve Falkenburg-- MacDTS
  7. ©1991-1993 Apple Computer, Inc.
  8.  
  9. --------------
  10. change history
  11. --------------
  12.  
  13. SJF        02/19/93    update for beta build    b1
  14. SJF        10/29/92    update to a11            a11
  15. SJF        06/08/92    update to a8            a8
  16. SJF        02/15/92    first working version    a4.5
  17. SJF        10/16/91    initial coding            a3
  18.  
  19. ---------------------------------------------------------------------*/
  20.  
  21. #include <ctype.h>
  22. #include <string.h>
  23.  
  24. #include "const.h"
  25. #include "gwerrors.h"
  26. #include "mytypes.h"
  27. #include "globals.h"
  28. #include "utils.h"
  29. #include "parser.h"
  30. #include "network.h"
  31. #include "smtp.protocol.h"
  32.  
  33. /*    This call takes a FULLY FORMED RFC-822 format message as input, and sends the message
  34.     using SMTP to the specified host
  35.     
  36.     the text is sent in "text" in the form of a zero-terminated C string
  37.     the sender is specified in "fromAddress"
  38.     the SMTP server is specified in "smtpServerAddress"
  39. */
  40.  
  41. OSErr SendSMTP(char *text,char *bccText,char *fromAddress,unsigned long smtpServerAddress)
  42. {
  43.     unsigned long stream;
  44.     Ptr response;
  45.     unsigned long responseLength;
  46.     OSErr err;
  47.     char *command;
  48.     char *lfText;
  49.     
  50.     TCP_FlushBytes();            // flush out old TCP response data
  51.     
  52.     command = nil;
  53.     stream = 0L;
  54.     
  55.     err = AddLF(text,&lfText);    // add linefeeds to message
  56.     if (err!=noErr) {
  57.         ExitSMTP(stream,nil,command);
  58.         return err;
  59.     }
  60.     strcat(lfText,kMessageTerminator);    // terminate message with '.'
  61.  
  62.     command = (char *)NewPtrChk(kSMTPCommandLength);
  63.     if (MemError()!=noErr) {
  64.         return MemError();
  65.     }
  66.     
  67.     err = TCP_CreateStream(&stream);
  68.     if (err!=noErr) {
  69.         ExitSMTP(stream,lfText,command);
  70.         return err;
  71.     }
  72.     
  73.     err = TCP_ActiveOpen(stream,smtpServerAddress,kSMTPPort,kSMTPTimeout);
  74.     if (err!=noErr) {
  75.         ExitSMTP(stream,lfText,command);
  76.         return kInvalidSMTPServer;
  77.     }
  78.     
  79.     /* get introduction message */
  80.         
  81.     err = SMTP_GetResponse(stream,&response,&responseLength);
  82.     if (err!=noErr) {
  83.         ExitSMTP(stream,lfText,command);
  84.         return err;
  85.     }
  86.     else if (!PositiveResponse(response)) {
  87.         DisposPtrChk(response);
  88.         ExitSMTP(stream,lfText,command);
  89.         return kSMTPError;
  90.     }
  91.     DisposPtrChk(response);
  92.     
  93.     /* send "HELO" message */
  94.     
  95.     strcpy(command,"HELO [");
  96.     strcat(command,gOurIPString);
  97.     strcat(command,"]");
  98.     err = SMTP_Command(stream,command,&response,&responseLength);
  99.     if (err!=noErr) {
  100.         ExitSMTP(stream,lfText,command);
  101.         return err;
  102.     }
  103.     else if (!PositiveResponse(response)) {
  104.         DisposPtrChk(response);
  105.         ExitSMTP(stream,lfText,command);
  106.         return kSMTPError;
  107.     }
  108.     DisposPtrChk(response);
  109.     
  110.     /* specify sender with MAIL FROM:<> field */
  111.     
  112.     strcpy(command,"MAIL FROM:<");
  113.     strcat(command,fromAddress);
  114.     strcat(command,">");
  115.     err = SMTP_Command(stream,command,&response,&responseLength);
  116.     if (err!=noErr) {
  117.         ExitSMTP(stream,lfText,command);
  118.         return err;
  119.     }
  120.     else if (!PositiveResponse(response)) {
  121.         DisposPtrChk(response);
  122.         ExitSMTP(stream,lfText,command);
  123.         return kSMTPError;
  124.     }
  125.     DisposPtrChk(response);
  126.  
  127.     /* add message recipients in RCPT TO:<> field */
  128.     
  129.     err = RcptMsg(lfText,stream,"To:");
  130.     if (err!=noErr) {
  131.         ExitSMTP(stream,lfText,command);
  132.         return err;
  133.     }        
  134.     err = RcptMsg(lfText,stream,"Cc:");
  135.     if (err!=noErr) {
  136.         ExitSMTP(stream,lfText,command);
  137.         return err;
  138.     }        
  139.     err = RcptMsg(bccText,stream,"Bcc:");
  140.     if (err!=noErr) {
  141.         ExitSMTP(stream,lfText,command);
  142.         return err;
  143.     }        
  144.     
  145.     /* send DATA command */
  146.     
  147.     err = SMTP_Command(stream,"DATA",&response,&responseLength);
  148.     if (err!=noErr) {
  149.         ExitSMTP(stream,lfText,command);
  150.         return err;
  151.     }
  152.     else if (!PositiveResponse(response)) {
  153.         DisposPtrChk(response);
  154.         ExitSMTP(stream,lfText,command);
  155.         return kSMTPError;
  156.     }
  157.     DisposPtrChk(response);
  158.     
  159.     /* send message contents */
  160.  
  161.     err = SMTP_Command(stream,lfText,&response,&responseLength);
  162.     if (err!=noErr) {
  163.         ExitSMTP(stream,lfText,command);
  164.         return err;
  165.     }
  166.     else if (!PositiveResponse(response)) {
  167.         DisposPtrChk(response);
  168.         ExitSMTP(stream,lfText,command);
  169.         return kSMTPError;
  170.     }
  171.     DisposPtrChk(response);
  172.     
  173.     /* send QUIT to terminate session */
  174.     
  175.     err = SMTP_Command(stream,"QUIT",&response,&responseLength);
  176.     if (err!=noErr) {
  177.         ExitSMTP(stream,lfText,command);
  178.         return err;
  179.     }
  180.     else if (!PositiveResponse(response)) {
  181.         DisposPtrChk(response);
  182.         ExitSMTP(stream,lfText,command);
  183.         return kSMTPError;
  184.     }
  185.     DisposPtrChk(response);
  186.     
  187.     ExitSMTP(stream,lfText,command);
  188.     return err;
  189. }
  190.  
  191.  
  192. void ExitSMTP(unsigned long stream,Ptr lfText,char *command)
  193. {
  194.     if (lfText)
  195.         DisposPtrChk(lfText);
  196.         
  197.     if (command) {
  198.         DisposPtrChk(command);
  199.         TCP_CloseConnection(stream,kSMTPTimeout);
  200.         TCP_ReleaseStream(stream);
  201.     }
  202. }
  203.     
  204.  
  205.  
  206. /*    RcptMsg determines the recipients of the message and sends commands
  207.     to the SMTP server specifying these people as recipients.
  208. */
  209.  
  210. OSErr RcptMsg(char *text,unsigned long stream,char *header)
  211. {
  212.     OSErr err;
  213.     char *command;
  214.     Ptr response;
  215.     unsigned long responseLength;
  216.     char recipient[256];
  217.     char *endOfHeader,*lineEnd,*curLine,*tmpWord;
  218.     
  219.     endOfHeader = strstr(text,kHeaderTerminator);
  220.     if (!endOfHeader)
  221.         return noErr;
  222.  
  223.     command = (char *)NewPtrChk(kSMTPCommandLength);
  224.     if (MemError()!=noErr) {
  225.         return MemError();
  226.     }
  227.  
  228.     lineEnd = text;
  229.     while (lineEnd < endOfHeader) {
  230.         GetLine(&curLine,&lineEnd);
  231.         if (strstr(curLine,header)==curLine) {
  232.             GetWord(&tmpWord,&curLine);
  233.             while (*curLine && curLine<lineEnd) {
  234.                 GetWord(&tmpWord,&curLine);
  235.                 if (curLine<=lineEnd) {
  236.                     CopyWord(recipient,tmpWord);
  237.                     
  238.                     /* add recipient */
  239.                     strcpy(command,"RCPT TO:<");
  240.                     strcat(command,recipient);
  241.                     strcat(command,">");
  242.                     err = SMTP_Command(stream,command,&response,&responseLength);
  243.                     if (err!=noErr && !PositiveResponse(response)) {
  244.                         return err;
  245.                     }
  246.                     DisposPtrChk(response);
  247.  
  248.                 }
  249.             }
  250.         }
  251.     }
  252.  
  253.     return err;
  254. }
  255.  
  256.  
  257. OSErr SMTP_Command(unsigned long connID,char *command,Ptr *response,unsigned long *responseLength)
  258. {
  259.     Ptr sendCommand;
  260.     unsigned short sendLength;
  261.     OSErr err;
  262.     
  263.     sendLength = strlen(command)+2;
  264.     sendCommand = NewPtrChk((long)sendLength+1);
  265.     if (MemError()!=noErr)
  266.         return MemError();
  267.         
  268.     strcpy(sendCommand,command);
  269.     strcat(sendCommand,kCRLF);
  270.     
  271.     err = TCP_Send(connID,sendCommand,sendLength,true,kSMTPTimeout);
  272.     if (err!=noErr) {
  273.         DisposPtrChk(sendCommand);
  274.         return err;
  275.     }
  276.     
  277.     err = SMTP_GetResponse(connID,response,responseLength);
  278.     DisposPtrChk(sendCommand);
  279.     return err;
  280. }
  281.  
  282.  
  283. OSErr SMTP_GetResponse(unsigned long connID,Ptr *response,unsigned long *responseLength)
  284. {
  285.     OSErr err;
  286.     Boolean inMultiLine;
  287.     unsigned short bytesReceived,bytesLeft,lineBytesReceived;
  288.     Ptr responseBuffer,lineStartPtr;
  289.     unsigned char netByte;
  290.     char extenderString[5];
  291.     
  292.     *response = nil;
  293.     inMultiLine = false;
  294.     bytesReceived = 0;
  295.     bytesLeft = kSMTPCommandLength-1;
  296.     lineBytesReceived = 0;
  297.     
  298.     *response = responseBuffer = NewPtrChk(kSMTPCommandLength);
  299.     if (MemError()!=noErr)
  300.         return MemError();
  301.     *responseBuffer = '\0';
  302.     
  303.     do {
  304.         lineStartPtr = responseBuffer;
  305.         do {
  306.             err = TCP_ReadByte(connID,&netByte,kSMTPTimeout);
  307.             if (err==noErr) {
  308.                 *responseBuffer++ = netByte;
  309.                 *responseBuffer = '\0';
  310.                 bytesReceived++;
  311.                 bytesLeft--;
  312.             }
  313.         } while (err==noErr && bytesLeft>0 && netByte!=LF);
  314.         inMultiLine = CheckExtendedReply(inMultiLine,lineStartPtr,responseBuffer,extenderString);
  315.     } while (inMultiLine);
  316.     
  317.     *responseLength = bytesReceived;
  318.     
  319.     return err;
  320. }
  321.  
  322.  
  323. Boolean CheckExtendedReply(Boolean inExtendedReply,Ptr lineStart,Ptr curPtr,char *extenderString)
  324. {
  325.     if ((curPtr-lineStart) < 4)
  326.         return false;
  327.     
  328.     if (!inExtendedReply && lineStart[3]==kExtenderChar) {
  329.         if (isdigit(lineStart[0]) && isdigit(lineStart[1]) && isdigit(lineStart[2])) {
  330.             BlockMove(lineStart,extenderString,3);
  331.             extenderString[3] = ' ';
  332.             extenderString[4] = '\0';
  333.             return true;
  334.         }
  335.     }
  336.     
  337.     if (inExtendedReply && strncmp(lineStart,extenderString,4)==0)
  338.         return false;
  339.     
  340.     return inExtendedReply;
  341. }
  342.  
  343.  
  344. Boolean PositiveResponse(char *response)
  345. {
  346.     if (*response > '3')
  347.         return false;
  348.     
  349.     return true;
  350. }
  351.